package NWish.json
{
	import NWish.Logger;
	
	import com.adobe.serialization.json.JSONDecoder;
	
	import NWish.Interface.ILogger;
	
	
	public class Json
	{
		public static function encode( o:Object ):String
		{
			try
			{
				var s = new MyJSONEncoder( o ).getString();
				
				var pattern:RegExp = new RegExp('"#_spaceline_','g');
				s = s.replace(pattern,'\n"');
				
				/*var pattern:RegExp = new RegExp('"#_spacelinebegin_*?#_end_','g');
				s = s.replace(pattern,'\n\n#line"');*/
				return s;
			}
			catch(e)
			{
				ILogger.log(e);
			}
			return '';
		}
		
		public static function decode( s:String, strict:Boolean = false ):*
		{	
			try
			{
				return new JSONDecoder( s, strict ).getValue();
			}
			catch(e)
			{
				ILogger.log(e);
				
				return new Object();
			}
		}
	}

}


import NWish.json.OrderDict;

import com.adobe.serialization.json.JSONEncoder;

import flash.geom.Vector3D;
import flash.utils.describeType;


class MyJSONEncoder extends JSONEncoder
{
	private var _tabNum = 0;
	private var _tabStr = 0;
	
	public function MyJSONEncoder( value:* )
	{
		super(value);
	}
	
	protected function get tabNum()
	{
		return _tabNum;
	}
	protected function set tabNum(num)
	{
		_tabNum = num;
		
		_tabStr = '';
		for(var i = 0; i < _tabNum; ++i)
		{
			_tabStr += '	';
		}
	}
	
	override protected function convertToString( value:* ):String
	{
		var s = super.convertToString(value);
		
		return s + '\n';
	}
	
	override protected function objectToString( o:Object ):String
	{
		++tabNum;
		
		var s:String = "";
		
		if ( o is OrderDict )
		{
			s = orderDictToString(o as OrderDict)
		}
		else if ( o is Vector3D )
		{
			s = vector3DToString(o as Vector3D)
		}
		else if ( o is Object )
		{
			var classInfo:XML = describeType( o );
			if ( classInfo.@name.toString() == "Object" )
			{
				s = __objectToString(o);
			}
			else // o is a class instance
			{
				s = classInstanceToString(o,classInfo);
			}
		}
		

		--tabNum;
		
		return '\n' + _tabStr + "{\n" + s + _tabStr + "}";
	}
	
	protected function orderDictToString( orderDict:OrderDict ):String
	{
		var s:String = "";
		
		orderDict.eachKeyValue(_eachKeyValue);
		
		function _eachKeyValue( key, value )
		{
			if ( value is Function )
				return;
			
			if ( s.length > 0 )
				s += ",";
			
			s += _tabStr + escapeString( key ) + "	:	" + convertToString( value );
		}
		
		return s;
	}
	
	override protected function arrayToString( a:Array ):String
	{
		++tabNum;
		
		var s:String = "";

		for ( var i:int = 0; i < a.length; i++ ) {

			if ( s.length > 0 ) {

				s += ","
			}
			
			s +=  _tabStr + convertToString( a[i] );	
		}
		
		--tabNum;
		
		return '\n' + _tabStr + "[\n" + s + _tabStr + "]";
	}
	
	protected function vector3DToString( v:Vector3D )
	{
		var s:String = "";
		
		s += _tabStr + escapeString( 'x' ) + "	:	" + convertToString( v.x ) + ",";
		s += _tabStr + escapeString( 'y' ) + "	:	" + convertToString( v.y ) + ",";
		s += _tabStr + escapeString( 'z' ) + "	:	" + convertToString( v.z ) + ",";
		s += _tabStr + escapeString( 'w' ) + "	:	" + convertToString( v.w );
		
		return s;
	}
	
	protected function __objectToString( o:Object ):String
	{
		var s:String = "";
		
		var value:Object;
		
		for ( var key:String in o )
		{
			value = o[key];
			
			if ( value is Function )
				continue;
			
			if ( s.length > 0 )
				s += ","
			
			s += _tabStr + escapeString( key ) + "	:	" + convertToString( value );
		}
		
		return s;
	}
	
	protected function classInstanceToString( o:Object, classInfo ):String
	{
		var s:String = "";
		
		for each ( var v:XML in classInfo..*.( 
			name() == "variable"
			||
			( 
				name() == "accessor"
				&& attribute( "access" ).charAt( 0 ) == "r" ) 
		) )
		{
			if ( v.metadata && v.metadata.( @name == "Transient" ).length() > 0 )
				continue;
			
			if ( s.length > 0 )
				s += ","
			
			s += _tabStr + escapeString( v.@name.toString() ) + "	:	" 
				+ convertToString( o[ v.@name ] );
		}
		
		return s;
	}
	
}

